#!coding:utf-8
'''
Created on Oct 17, 2012

@author: join

'''

from lottery_terminal.rpc import rbc
from xml.dom.minidom import parseString
from django.db import transaction
import datetime
from lottery_terminal.models import Period, Trade, TicketConstant, TicketLoan,\
    FiveBall, SevenColor, SixPlusOne, ThreeD, Account
import logging
from lottery_terminal.common import utils, Constant
import json
import uuid

lotterycode_dict = {"20":0,'01':1,'07':2,'05':3,'15':4,'06':5}
_ticket_obj = {'20':TicketConstant,'01':TicketLoan,'07':SevenColor,'05':ThreeD,'15':FiveBall,'06':SixPlusOne}
lotterycode_desc = {"20":u'时时彩','01':u'双色球','07':u'七乐彩','05':u'福彩3D','15':u'15选5','06':u'东方6+1'}
ticket_model_ticket = {1:TicketLoan,0:TicketConstant,2:SevenColor,3:ThreeD,4:FiveBall,5:SixPlusOne}
LOG = logging.getLogger('terminal')

class BaseLottery(object):
    '''彩票业务层基本类，存放彩票业务的公有方法'''
    def __init__(self,lotterycode):
        self.lotterycode = lotterycode
        self.lotterycode_db = lotterycode_dict.get(lotterycode)
        self.dom=None
    
    def is_result_ok(self,res_xml):
        if res_xml.find('encoding="gb2312"')!=-1:
            res_xml = res_xml.replace('encoding="gb2312"', 'encoding="utf-8"')
        elif res_xml.find('encoding="gbk"')!=-1:
            res_xml = res_xml.replace('encoding="gbk"', 'encoding="utf-8"')
        self.dom = parseString(res_xml)
        resp_node = self.dom.getElementsByTagName("Resp")[0]
        errcode = resp_node.getAttribute("errcode")
        result,status = True if int(errcode)==0 else False,errcode
        return result,status
    
    def is_buytime(self,currenttime=None):
        '''验证当前时间是否为购买彩票时间'''
        if not currenttime:
            currenttime = datetime.datetime.now()  #TODO:提醒，考虑时间的一致性问题
        periods = Period.objects.filter(lotterycode=self.lotterycode,endtime__lte=currenttime,awardtime__gt=datetime.datetime.now())
        result = True if not periods else False #期次存在，则为非购买彩票时间False
        return result,periods

    def get_current_period(self,pre_stop):
        try:
            currenttime1 = datetime.datetime.now()
            currenttime = currenttime1+datetime.timedelta(minutes=pre_stop) #将当前时间往后推,本系统的开奖时间需要比第三方接口的开奖时间做相应提前
            is_buy_time,period_s = self.is_buytime(currenttime=currenttime)
            if not is_buy_time:
                if not period_s:#开奖时间，缺少当前期次信息
                    self.download_periods(self.lotterycode)
                    period_s = Period.objects.filter(starttime__lte=currenttime1,awardtime__gt=currenttime1,lotterycode=self.lotterycode)
                return period_s[0],201
                
            periods = Period.objects.filter(starttime__lte=currenttime,endtime__gte=currenttime,lotterycode=self.lotterycode)
            if not periods: #当发现没有期次信息，下载期次信息到数据库
                self.download_periods(self.lotterycode)
                periods = Period.objects.filter(starttime__lte=currenttime,endtime__gte=currenttime,lotterycode=self.lotterycode)
            #返回期次信息
            return periods[0],200
        except Exception as e:
            LOG.exception('an exception occured,exception is:%s',e)
            raise e
    
    def query_award_code(self,periodid):
        '''查询开奖号码'''
        try:
            awardcode_xml = rbc.queryAwardCode(self.lotterycode,periodid)
            result = self.is_result_ok(awardcode_xml)[0]
            if result:
                awardnode = self.dom.getElementsByTagName('lottery')[0]
                awardcodes = awardnode.getAttribute('codes')
                if awardcodes:
                    if self.lotterycode == '01' or self.lotterycode=='07': #是双色球，对双色球进行排序
                        red,blue=awardcodes.split('|')
                        red = self.sort_award_codes(red.split(','))
                        awardcodes = red+'|'+blue
                    Period.objects.filter(deleted=False,lotterycode=self.lotterycode,periodid=periodid).update(awardcodes=awardcodes)
                return awardcodes
            else:
                return None
        except Exception as e:
            raise e
    
    
    def query_award_money(self,periodid):
        '''查询奖池，奖级数据,目前只有双色球和7乐彩有这个'''
        try:
            award_dict={}
            awardmoney_xml = rbc.queryAwardMoney(self.lotterycode,periodid)
        
            result = self.is_result_ok(awardmoney_xml)[0]
            if result:
                levels = self.dom.getElementsByTagName('level')
                lottery = self.dom.getElementsByTagName('lottery')
                poolmoney = lottery[0].getAttribute('poolmoney')
                
                awardcodes = lottery[0].getAttribute('codes')
                if awardcodes:
                    if self.lotterycode == '01' or self.lotterycode=='07': #是双色球，对双色球进行排序
                        red,blue=awardcodes.split('|')
                        red = self.sort_award_codes(red.split(','))
                        awardcodes = red+'|'+blue
                    Period.objects.filter(lotterycode=self.lotterycode,periodid=periodid).update(awardcodes=awardcodes)
                    
                if poolmoney:
                    Period.objects.filter(lotterycode=self.lotterycode,periodid=periodid).update(poolmoney=int(poolmoney.split(".")[0]))
                award_dict = dict(([level.getAttribute('index'),level.getAttribute('money')] for level in levels))
                return award_dict
            else:
                return None
        except Exception as e:
            LOG.error("an exception occured in query award money:%s"%e)
            return None
    
    
    def query_award_list(self,periodid,page=1):
        '''查询中奖者名单'''
        _model = _ticket_obj.get(self.lotterycode) #ticket表
        res_xml = rbc.queryAwardList(self.lotterycode, periodid, page=page)
        result = self.is_result_ok(res_xml)
        
        if result:
            Period.objects.filter(deleted=False,periodid=periodid,lotterycode=self.lotterycode).update(status=1)
            resp_node = self.dom.getElementsByTagName("Resp")[0]
            total_pages = int(resp_node.getAttribute("totals"))
            award_nodes = self.dom.getElementsByTagName("award")
            compay_balance2add = 0
            for award_node in award_nodes:
                award_info = award_node.getAttribute("info").split('_')
                businessid = award_info[0]
                prizemoney = award_info[4]
                hasbigprize = award_info[5]
                if hasbigprize=='0':
                    compay_balance2add += int(prizemoney)
                _model.objects.filter(businessid=businessid).update(prizemoney=prizemoney,hasbigprize=hasbigprize) #查出该流水号的彩票
    #            if not tickets:
    #                LOG.exception("Exception:a ticket appeared in awardList,but not in database.")
    #                continue
            account_company = Account.objects.filter(accountType=2,deleted=False)[0]
            newbalance = account_company.balance + float(compay_balance2add)
            account_company.balance = newbalance
            LOG.exception("query_award_list:add balance to account:%s,money:%s,new balance:%s"%(account_company.account,float(compay_balance2add),newbalance))
            account_company.save()
            left_pages = total_pages - page #剩下多少页的数据没有查询出来
            if left_pages>0: #递归调用该方法，直到所有中奖名单全部查询出来
                self.query_award_list(periodid,(page+1))
            return True
        else:
            return False
    
    @transaction.commit_on_success
    def download_periods(self,lotterycode):
        '''下载当前期次信息,并保存到数据库中'''
        try:
            periods_xml = rbc.get_periods(lotterycode)
            if periods_xml.find('encoding="gb2312"')!=-1:
                periods_xml = periods_xml.replace('encoding="gb2312"', 'encoding="utf-8"')
            elif periods_xml.find('encoding="gbk"')!=-1:
                periods_xml = periods_xml.replace('encoding="gbk"', 'encoding="utf-8"')
            dom = parseString(periods_xml)
        
            resp_node = dom.getElementsByTagName("Resp")[0]
            errcode = resp_node.getAttribute("errcode")
            if int(errcode) != 0:
                raise Exception(u'下载期次信息失败')
        
            period_nodes = dom.getElementsByTagName('period')
            for node in period_nodes:
                periodid = node.getAttribute('id')
                starttime = node.getAttribute('starttime')
                endtime = node.getAttribute('endtime')
                awardtime = node.getAttribute('awardtime')
                if not periodid or not starttime or not endtime or not awardtime:
                    raise Exception('node %s has an empty attribute' % periodid)
            
                currenttime = datetime.datetime.now()
                if utils.format_datetime(starttime) <= currenttime <= utils.format_datetime(awardtime): #上一期次的时时彩开奖结束后，中心会调整期次信息，因此需要每次查询接口
                    periods=Period.objects.filter(deleted=False,periodid=periodid,lotterycode=lotterycode)
                    if periods:
                        LOG.debug("period already exists,break directly.")
                        return periods[0]
                    period=Period.objects.create(periodid=periodid,starttime=starttime,endtime=endtime,awardtime=awardtime,lotterycode=lotterycode,status=0)
                    return period
        except Exception as e:
            LOG.exception("exception is:%s" % e)
            raise e
        
    #购买彩票
    @transaction.commit_on_success
    def buy_ticket(self,ticket_infos): #codes,periodid,identifycard,itentifyname,buymethod,prizetype):
        '''彩票号码信息组，期次id，身份证号码，真实姓名，购买方式，返奖方式'''
        #修改账户的额度账户，或者银联扣款
        account = ticket_infos['account']
        buymethod = ticket_infos['buymethod']
        trade_amount = ticket_infos['tradeAmount']
        
        tianfu_account = ticket_infos['tianfu_account']
        period = ticket_infos['period']
        
        ##处理每个彩种的号码格式
        tradetime = utils.now()
        sd_batchid = (uuid.uuid1()).get_hex()
        result = self.handle_codes(ticket_infos,tradetime,sd_batchid)
        
        codes_handled = result['codes_handled']
#        trades = result['trades']
        num_list = result['num_list']
         
        res_xml = rbc.lottery_sd(codes_handled,self.lotterycode,period.periodid,sd_batchid)[0] #投注号码，彩种
        #解析xml返回结果，查看是否交易成功
        sdresult = self.is_result_ok(res_xml)[0]
        if not sdresult: #修改交易状态为失败
            self.handle_querycast_result(False, sd_batchid)
            cast_msg = u'福彩中心出票失败'
            status = 500
            return cast_msg,status
        else:
            cast_msg=u'出票成功,打印彩票'
        
            #扣除公司额度账户相应余额
            company_sale_awards = trade_amount*tianfu_account.commissionRatio
            ratio = account.commissionRatio if account.commissionRatio else 0.07
            saler_sale_awards = trade_amount*ratio
            tianfu_account.balance = tianfu_account.balance-trade_amount+company_sale_awards
            tianfu_account.save()
            
            LOG.exception("buy_ticket:add balance to account:%s,money:%s,new balance:%s"%(tianfu_account.account,float(company_sale_awards),tianfu_account.balance))
            
            if buymethod == str(Constant.TRADEMETHOD_CARD):
                account.balance = account.balance+saler_sale_awards
                
                LOG.exception("buy_ticket:add balance to account:%s,money:%s,new balance:%s"%(account.account,saler_sale_awards,account.balance))
                
            else: #非银联支付，扣除额度账户的相应值
                account.balance = account.balance-trade_amount+saler_sale_awards
                LOG.exception("buy_ticket:add balance to account:%s,money:%s,new balance:%s,time:%s"%(account.account,saler_sale_awards,account.balance))
                
            account.save()
    
            status = 200
            
        validity_time = period.awardtime + datetime.timedelta(days=self.validityday)
        data = {
          'wanfa':lotterycode_desc[self.lotterycode],
          'jihao':account.account,
          'periodid':period.periodid,
          'validity':utils.convert_datetime_to_str(validity_time, '%Y-%m-%d'),
          'buytime':utils.convert_datetime_to_str(tradetime, '%Y-%m-%d %H:%M:%S'),
          #'trade_amount':'%s'%ticket_infos['tradeAmount'],
          'awardtime':utils.convert_datetime_to_str(period.awardtime, '%Y-%m-%d %H:%M:%S'),
          'phonenumber':rbc.telephone,
          'msg' : cast_msg,
          'sd_batchid':sd_batchid,
          'num_list':num_list}
        LOG.info("data is:%s"%data)
        return json.dumps(data),status
    
    
    def handle_querycast_result(self,result,sd_batchid):
        '''处理出票结果,出票成功，失败均更新数据库trade表和lottery表状态'''
        try:
            status = 2 if result else 1
#            if result: #出票成功
#                pass
#            else:
            Trade.objects.filter(desc=sd_batchid).update(status=status)
            self.ticketobj.objects.filter(tradeId__desc=sd_batchid).update(status=status)
        except Exception as e:
            LOG.exception("an exception occured in handle_querycast_result:%s"%e)
        
    def handle_codes(self,ticket_infos,tradetime,sd_batchid):
        '''处理双色球彩票号码，包括单式，复式，胆托'''
        result = {}
        code_danshi=[]
        code_fuza=[]
        codes_handled = [] #用来向第三方接口进行交互的号码格式
        num_list = [] #打印到彩票上的号码组信息
        
        ticket_codes = ticket_infos['codes'] #前台传过来的彩票号码信息组
        period = ticket_infos['period']
        
        batchid = utils.generate_batchid()
#        hmid = uuid.uuid1().get_hex()
        hmid = batchid
        index = 0
        validitytime = period.awardtime + datetime.timedelta(days=self.validityday)
        
        for code in ticket_codes:
            ccodes = code.split('#')
            if int(ccodes[2])==1:
                code_danshi.append(code)
            else:
                code_fuza.append(code)
#            code = ':'.join(ccodes[:-1])
#            codes_handled.append('%s-%s_%s'%(batchid,(index+1),code))
         
        #dantuo票
        for fuza_code in code_fuza:
            index += 1
            codes = fuza_code.split('#')
            #对每张彩票都记录流水号，以方便做是否中奖比对
            code = ':'.join(codes[:-1])
            businessid = '%s-%s' % (hmid,index)
            codes_handled.append('%s_%s'%(businessid,code))
            
            tradeamount = int(codes[-1])
            ticket_amount = int(codes[-2])
            buy_money = int(codes[-1])
      
            batchid = '%s' % (int(batchid)+1)
            trade = Trade(tradeType=1,tradeTicketType=self.lotterycode_db,tradeMethod=ticket_infos['buymethod'],tradeAmount=tradeamount,period=period,
                    accountid=ticket_infos['account'],tradeTime=tradetime,status=0,prizeType=ticket_infos['prizeType'],batchid=batchid,desc=sd_batchid) #创建一条交易记录，状态为交易完成，如果失败再改回来。
            trade.save()
            num_list.append({'batchid':batchid,'num':['%s' % fuza_code.split('#')[0]],'fs':self.fs_dict.get(codes[2]),'tradeamount':tradeamount,'beishu':ticket_amount})
            self.ticketobj.objects.create(lotteryNumber=':'.join(fuza_code.split('#')[:-1]),ticketamount=ticket_amount,buytime=tradetime,
                          validitytime=validitytime,status=0,buymoney=buy_money,tradeId=trade,businessid=businessid)  #创建彩票记录到数据库,状态为交易完成，如果失败，需要改变这个状态
#            
        #单式
        ds_count = 0 #每5注保存为一个交易
        tradeamount = 0
        for ds_code in code_danshi:
            index += 1
            codes = ds_code.split('#')
            ticket_amount = int(codes[-2])
            #对每张彩票都记录流水号，以方便做是否中奖比对
            code = ':'.join(codes[:-1])
            businessid = '%s-%s' % (hmid,index)
            codes_handled.append('%s_%s'%(businessid,code))
            
            if ds_count%5 == 0:
                tradeamount = sum([int(t.split('#')[-1]) for t in code_danshi[ds_count:ds_count+5]])
                batchid = '%s' % (int(batchid)+1)
                num_list.append({'batchid':batchid,'num':['%s'%t.split('#')[0] for t in code_danshi[ds_count:ds_count+5]],
                                 'fs':self.fs_dict.get(codes[2]),'tradeamount':tradeamount,'beishu':ticket_amount})
                trade = Trade(tradeType=1,tradeTicketType=self.lotterycode_db,tradeMethod=ticket_infos['buymethod'],tradeAmount=tradeamount,period=period,
                              accountid=ticket_infos['account'],tradeTime=tradetime,status=0,prizeType=ticket_infos['prizeType'],batchid=batchid,desc=sd_batchid) #创建一条交易记录，状态为交易中
                trade.save()
            
            ds_count += 1
            buy_money = int(codes[-1])
            ds_code = ':'.join(codes[:-1])
            self.ticketobj.objects.create(lotteryNumber=ds_code,ticketamount=ticket_amount,buytime=tradetime,
                validitytime=validitytime,status=0,buymoney=buy_money,tradeId=trade,businessid=businessid)  #创建彩票记录
        
#        result['trades'] = trades
        result['codes_handled'] = codes_handled
        result['num_list'] = num_list
        return result
    
    def sort_award_codes(self,codes):
        '''对开奖号码进行从小到大排序'''
        codes.sort(key=lambda x:int(x))
        return ','.join(codes)
            